package com.douding.file.controller.admin;

import com.douding.server.domain.Test;
import com.douding.server.dto.FileDto;
import com.douding.server.dto.ResponseDto;
import com.douding.server.enums.FileUseEnum;
import com.douding.server.service.FileService;
import com.douding.server.service.TestService;
import com.douding.server.util.Base64ToMultipartFile;
import com.douding.server.util.UuidUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.util.List;

/*
    返回json 应用@RestController
    返回页面  用用@Controller
 */
@RequestMapping("/admin/file")
@RestController
public class UploadController {

    private static final Logger LOG = LoggerFactory.getLogger(UploadController.class);
    public  static final String BUSINESS_NAME ="文件上传";

    @Value("${file.path}") // D:\douding\
    private String FILE_PATH;

    @Value("${file.domain}") // http://127.0.0.1:9000/file/f/
    private String FILE_DOMAIN;

    @Resource
    private FileService fileService;

    @RequestMapping("/upload")
    public ResponseDto upload(@RequestBody FileDto fileDto) throws Exception {

        // 将分片转为 MultipartFile
        MultipartFile shard = Base64ToMultipartFile.base64ToMultipart(fileDto.getShard());
        //  获取分片要保存到的路径
        //  根据use字段获取文件用途，从而上传到不同文件夹下
        String use = fileDto.getUse();
        FileUseEnum useEnum = FileUseEnum.getByCode(use);
        String dir = useEnum.name().toLowerCase();// dir 为 course 或者 teacher
        // 创建目录
        File fullDir = new File(FILE_PATH + dir);
        if (!fullDir.exists()) {
            // 如果目录不存在，则创建目录
            fullDir.mkdir();
        }

        String key = fileDto.getKey();
        String suffix = fileDto.getSuffix();
        // 配置文件的相对路径
        String path = dir + "/" + key + "." + suffix; // course\6sfSqfOwzmik4A4icMYuUe.mp4
        // 给文件配置带有分片数量的后缀的路径名
        String localPath = path + "." + fileDto.getShardIndex(); // course\6sfSqfOwzmik4A4icMYuUe.mp4.1
        // 拼接保存在磁盘中的路径
        String fullPath = FILE_PATH + localPath;
        //创建目标文件
        File dest = new File(fullPath);
        //通过 transferTo 保存文件到服务器磁盘
        shard.transferTo(dest);
        // 将文件分片信息保存/更新到数据库
        fileDto.setPath(path);
        fileService.save(fileDto);

        // 若分片均已上传，将所有分片合并成一个文件。
        if (fileDto.getShardTotal().equals(fileDto.getShardIndex())) {
            this.merge(fileDto);
        }

        // 返回分片上传结果
        ResponseDto<FileDto> responseDto = new ResponseDto<>();
        responseDto.setContent(fileDto);
        // 设置图片的路径名，这样能将图片的路径名返回给前端
        fileDto.setPath(FILE_DOMAIN + path);
        return responseDto;
    }

    //合并分片
    public void merge(FileDto fileDto) throws Exception {
        LOG.info("合并分片开始");
        String path = fileDto.getPath();
        Integer shardTotal = fileDto.getShardTotal();
        File newFile = new File(FILE_PATH + path);
        byte[] byt = new byte[10 * 1024 * 1024];
        FileInputStream inputStream = null;   // 分片文件
        int len;
        // 文件追加写入
        try (FileOutputStream outputStream = new FileOutputStream(newFile, true);) {
            for (int i = 0; i < shardTotal; i++) {
                // 读取每一个分片
                inputStream = new FileInputStream(FILE_PATH + path + "." + (i+1)); // course\6sfSqfOwzmik4A4icMYuUe.mp4.1
                while ((len = inputStream.read(byt))!=-1) {
                    // 写入到 newFile 中
                    outputStream.write(byt, 0, len);
                }
            }
        } catch (FileNotFoundException e) {
            LOG.info("文件寻找异常", e);
        } catch (IOException e) {
            LOG.info("分片合并异常", e);
        } finally {
            // 必须将 IO 流关闭
            try {
                if(inputStream !=null) {
                    inputStream.close();
                }
                LOG.info("IO流关闭");
            } catch (IOException e) {
                LOG.error("IO流关闭", e);
            }

        }
        LOG.info("合并分片结束");

        // 将所有分片删除
        LOG.info("删除分片开始");
        for (int i = 0; i < shardTotal; i++) {
            // 遍历文件夹里的每个分片，并进行删除
            String filePath = FILE_PATH + path + "." + (i + 1);
            File file = new File(filePath);
            boolean result = file.delete();
            LOG.info("删除{}，{}", filePath, result ? "成功" : "失败");
        }
        LOG.info("删除分片结束");
    }

    @GetMapping("/check/{key}")
    public ResponseDto check(@PathVariable String key) throws Exception {
        LOG.info("检查上传分片开始：{}", key);

        // 从数据库中查询是否有该文件的记录
        FileDto fileDto = fileService.findByKey(key);

        ResponseDto<FileDto> responseDto = new ResponseDto<>();
        responseDto.setContent(fileDto);

        return responseDto;
    }

}//end class
